//
// Created by yuping.li on 10/14/24.
//

#ifndef TASK_HPP
#define TASK_HPP

#include <cstdint>
#include <memory>
#include "asm/context.h"
#include "platform/time.hpp"

class Task {
 public:
  virtual ~Task() = default;
  virtual void init_task() { };
  virtual void period_task() { };
  virtual void deinit_task() { };


  inline uint32_t get_period() const {
    return period_ms;
  }

  inline int64_t get_next_run_time() const {
    return next_run_time;
  }

  inline bool get_finished() const {
    return finished;
  }

  inline void cancle_period_task() {
    period_ms = UINT32_MAX;
  }

  inline void set_exit() {
    next_run_time = Time::instance().get_timestamp_ms();
    running = false;
  }

  const lcontext_t * get_entry_context() {
    return &entry_context;
  }

  void task_init(lcontext_t * context) {
    stack = std::make_unique<uint8_t[]>(stack_size);    //申请内存作为栈
    get_context(&entry_context);             //makecontext需要通过getcontext初始化一个ucontext
    entry_context.stack.ss_sp = stack.get();         //传递栈指针
    entry_context.stack.ss_size = stack_size;        //传递栈大小
//    entry_context.uc_link = context;                    //当新context运行完后的返回context，这里返回调度器的context
    make_context(&entry_context, (void*)task_helper, 1, this); //制造一个指向task_helper的context，并传递本类指针
    return_context = context;                           //设置返回context
    next_run_time = Time::instance().get_timestamp_ms();                 //设置next_run_time为当前时间戳，即期待马上切换该context
  }

 protected:
  static void task_helper(Task* t) {
    t->init_task();
    t->task_yield();
    while(t->running) {
      auto time_stamp = Time::instance().get_timestamp_ms();
      if (t->period_ms != UINT32_MAX) {
        t->period_task();
      }
      t->next_run_time = time_stamp + t->period_ms;
      t->raw_task_yield();
    }
    t->deinit_task();
    t->next_run_time = INT64_MAX;
    t->finished = true;
    t->raw_task_yield();
  }

  void task_yield() {
    next_run_time = Time::instance().get_timestamp_ms() + period_ms;
    swap_context(&entry_context, return_context);
  }

  void task_yield(int64_t sleep_time_ms) {
    next_run_time = Time::instance().get_timestamp_ms() + sleep_time_ms;
    swap_context(&entry_context, return_context);
  }

  void raw_task_yield() {
    swap_context(&entry_context, return_context);
  }

 protected:
  uint32_t period_ms{UINT32_MAX};
  lcontext_t entry_context{};
  lcontext_t * return_context{nullptr};
  std::unique_ptr<uint8_t[]> stack{nullptr};
  const uint32_t stack_size{1024};
  int64_t next_run_time{0};
  bool running{true};
  bool finished{false};
};



#endif //TASK_HPP
